package com.btsi.contract;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.v3.client.Client;
import org.fisco.bcos.sdk.v3.codec.abi.FunctionEncoder;
import org.fisco.bcos.sdk.v3.codec.datatypes.Address;
import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes;
import org.fisco.bcos.sdk.v3.codec.datatypes.Event;
import org.fisco.bcos.sdk.v3.codec.datatypes.Function;
import org.fisco.bcos.sdk.v3.codec.datatypes.Type;
import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.v3.contract.Contract;
import org.fisco.bcos.sdk.v3.crypto.CryptoSuite;
import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.v3.model.CryptoType;
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class TransparentUpgradeableProxy extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405260405162000a0438038062000a0483398101604081905262000026916200021f565b82816200003382620000c1565b805115620000aa576000826001600160a01b031682604051620000579190620002ff565b600060405180830381855af49150503d806000811462000094576040519150601f19603f3d011682016040523d82523d6000602084013e62000099565b606091505b5050905080620000a857600080fd5b505b50620000b890508262000184565b50505062000343565b620000d781620001b360201b620003501760201c565b6200014e5760405162461bcd60e51b815260206004820152603660248201527f5570677261646561626c6550726f78793a206e657720696d706c656d656e746160448201527f74696f6e206973206e6f74206120636f6e747261637400000000000000000000606482015260840160405180910390fd5b60006200017d60017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd6200031d565b9190915550565b60006200017d60017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61046200031d565b3b151590565b80516001600160a01b0381168114620001d157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000209578181015183820152602001620001ef565b8381111562000219576000848401525b50505050565b6000806000606084860312156200023557600080fd5b6200024084620001b9565b92506200025060208501620001b9565b60408501519092506001600160401b03808211156200026e57600080fd5b818601915086601f8301126200028357600080fd5b815181811115620002985762000298620001d6565b604051601f8201601f19908116603f01168101908382118183101715620002c357620002c3620001d6565b81604052828152896020848701011115620002dd57600080fd5b620002f0836020830160208801620001ec565b80955050505050509250925092565b6000825162000313818460208701620001ec565b9190910192915050565b6000828210156200033e57634e487b7160e01b600052601160045260246000fd5b500390565b6106b180620003536000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046105a1565b610118565b61005b6100933660046105c3565b61014d565b3480156100a457600080fd5b506100ad6101f4565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046105a1565b61022f565b3480156100f557600080fd5b506100ad610325565b610106610356565b6101166101116103f0565b610425565b565b610120610449565b6001600160a01b0316336001600160a01b031614156101455761014281610477565b50565b6101426100fe565b610155610449565b6001600160a01b0316336001600160a01b031614156101e75761017783610477565b6000836001600160a01b03168383604051610193929190610646565b600060405180830381855af49150503d80600081146101ce576040519150601f19603f3d011682016040523d82523d6000602084013e6101d3565b606091505b50509050806101e157600080fd5b50505050565b6101ef6100fe565b505050565b60006101fe610449565b6001600160a01b0316336001600160a01b031614156102245761021f6103f0565b905090565b61022c6100fe565b90565b610237610449565b6001600160a01b0316336001600160a01b03161415610145576001600160a01b0381166102d15760405162461bcd60e51b815260206004820152603a60248201527f5472616e73706172656e745570677261646561626c6550726f78793a206e657760448201527f2061646d696e20697320746865207a65726f206164647265737300000000000060648201526084015b60405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6102fa610449565b604080516001600160a01b03928316815291841660208301520160405180910390a1610142816104b7565b600061032f610449565b6001600160a01b0316336001600160a01b031614156102245761021f610449565b3b151590565b61035e610449565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4016102c8565b60008061041e60017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610656565b5492915050565b3660008037600080366000845af43d6000803e808015610444573d6000f35b3d6000fd5b60008061041e60017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104610656565b610480816104eb565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60006104e460017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104610656565b9190915550565b803b6105585760405162461bcd60e51b815260206004820152603660248201527f5570677261646561626c6550726f78793a206e657720696d706c656d656e74616044820152751d1a5bdb881a5cc81b9bdd08184818dbdb9d1c9858dd60521b60648201526084016102c8565b60006104e460017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610656565b80356001600160a01b038116811461059c57600080fd5b919050565b6000602082840312156105b357600080fd5b6105bc82610585565b9392505050565b6000806000604084860312156105d857600080fd5b6105e184610585565b9250602084013567ffffffffffffffff808211156105fe57600080fd5b818601915086601f83011261061257600080fd5b81358181111561062157600080fd5b87602082850101111561063357600080fd5b6020830194508093505050509250925092565b8183823760009101908152919050565b60008282101561067657634e487b7160e01b600052601160045260246000fd5b50039056fea26469706673582212207c57174660757dfbcd1426e042490ca015720bfe1ebc992bc26914f05fc7264f64736f6c634300080b0033"};

    public static final String BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"608060405260405162000a0838038062000a08833981016040819052620000269162000220565b82816200003382620000c1565b805115620000aa576000826001600160a01b03168260405162000057919062000300565b600060405180830381855af49150503d806000811462000094576040519150601f19603f3d011682016040523d82523d6000602084013e62000099565b606091505b5050905080620000a857600080fd5b505b50620000b890508262000185565b50505062000344565b620000d781620001b460201b620003511760201c565b6200014f57604051636381e58960e11b815260206004820152603660248201527f5570677261646561626c6550726f78793a206e657720696d706c656d656e746160448201527f74696f6e206973206e6f74206120636f6e747261637400000000000000000000606482015260840160405180910390fd5b60006200017e60017fc491a4bc7f22df3d1fef738d9a3c4c3d72de30f6f5b4b051104051df906485f76200031e565b9190915550565b60006200017e60017f1739bb05de6bfb1e46d9ecd038d53871bf808b66c6cb0c157e00eb42c2717ebb6200031e565b3b151590565b80516001600160a01b0381168114620001d257600080fd5b919050565b63b95aa35560e01b600052604160045260246000fd5b60005b838110156200020a578181015183820152602001620001f0565b838111156200021a576000848401525b50505050565b6000806000606084860312156200023657600080fd5b6200024184620001ba565b92506200025160208501620001ba565b60408501519092506001600160401b03808211156200026f57600080fd5b818601915086601f8301126200028457600080fd5b815181811115620002995762000299620001d7565b604051601f8201601f19908116603f01168101908382118183101715620002c457620002c4620001d7565b81604052828152896020848701011115620002de57600080fd5b620002f1836020830160208801620001ed565b80955050505050509250925092565b6000825162000314818460208701620001ed565b9190910192915050565b6000828210156200033f5763b95aa35560e01b600052601160045260246000fd5b500390565b6106b480620003546000396000f3fe60806040526004361061004e5760003560e01c8063207fa8b914610065578063667615ba14610078578063d5696bb114610098578063e8a8c894146100c9578063f1522800146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b61005b6100733660046105a4565b610118565b34801561008457600080fd5b5061005b610093366004610627565b6101bf565b3480156100a457600080fd5b506100ad6102c1565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e4366004610627565b6102fc565b3480156100f557600080fd5b506100ad610326565b610106610357565b6101166101116103f2565b610427565b565b61012061044b565b6001600160a01b0316336001600160a01b031614156101b25761014283610479565b6000836001600160a01b0316838360405161015e929190610649565b600060405180830381855af49150503d8060008114610199576040519150601f19603f3d011682016040523d82523d6000602084013e61019e565b606091505b50509050806101ac57600080fd5b50505050565b6101ba6100fe565b505050565b6101c761044b565b6001600160a01b0316336001600160a01b031614156102b9576001600160a01b03811661026257604051636381e58960e11b815260206004820152603a60248201527f5472616e73706172656e745570677261646561626c6550726f78793a206e657760448201527f2061646d696e20697320746865207a65726f206164647265737300000000000060648201526084015b60405180910390fd5b7f7fff140a2090a44f84000f793b3e2c26fd84de1b51418e5734481ecebf9fa41961028b61044b565b604080516001600160a01b03928316815291841660208301520160405180910390a16102b6816104b9565b50565b6102b66100fe565b60006102cb61044b565b6001600160a01b0316336001600160a01b031614156102f1576102ec6103f2565b905090565b6102f96100fe565b90565b61030461044b565b6001600160a01b0316336001600160a01b031614156102b9576102b681610479565b600061033061044b565b6001600160a01b0316336001600160a01b031614156102f1576102ec61044b565b3b151590565b61035f61044b565b6001600160a01b0316336001600160a01b0316141561011657604051636381e58960e11b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a401610259565b60008061042060017fc491a4bc7f22df3d1fef738d9a3c4c3d72de30f6f5b4b051104051df906485f7610659565b5492915050565b3660008037600080366000845af43d6000803e808015610446573d6000f35b3d6000fd5b60008061042060017f1739bb05de6bfb1e46d9ecd038d53871bf808b66c6cb0c157e00eb42c2717ebb610659565b610482816104ed565b6040516001600160a01b038216907f35c786da035a401a18e1a5dade4bdb4c07d82bdd5c15bef8561dbf76ad4db25d90600090a250565b60006104e660017f1739bb05de6bfb1e46d9ecd038d53871bf808b66c6cb0c157e00eb42c2717ebb610659565b9190915550565b803b61055b57604051636381e58960e11b815260206004820152603660248201527f5570677261646561626c6550726f78793a206e657720696d706c656d656e74616044820152751d1a5bdb881a5cc81b9bdd08184818dbdb9d1c9858dd60521b6064820152608401610259565b60006104e660017fc491a4bc7f22df3d1fef738d9a3c4c3d72de30f6f5b4b051104051df906485f7610659565b80356001600160a01b038116811461059f57600080fd5b919050565b6000806000604084860312156105b957600080fd5b6105c284610588565b9250602084013567ffffffffffffffff808211156105df57600080fd5b818601915086601f8301126105f357600080fd5b81358181111561060257600080fd5b87602082850101111561061457600080fd5b6020830194508093505050509250925092565b60006020828403121561063957600080fd5b61064282610588565b9392505050565b8183823760009101908152919050565b6000828210156106795763b95aa35560e01b600052601160045260246000fd5b50039056fea2646970667358221220884bc9cfaa648afd459182fc757138c9f04d80934633cb9aad43098a7856cbd564736f6c634300080b0033"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_adm\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_ADMIN = "admin";

    public static final String FUNC_CHANGEADMIN = "changeAdmin";

    public static final String FUNC_IMPLEMENTATION = "implementation";

    public static final String FUNC_UPGRADETO = "upgradeTo";

    public static final String FUNC_UPGRADETOANDCALL = "upgradeToAndCall";

    public static final Event ADMINCHANGED_EVENT = new Event("AdminChanged",
            Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Address>() {}));
    ;

    public static final Event UPGRADED_EVENT = new Event("Upgraded",
            Arrays.<TypeReference<?>>asList(new TypeReference<Address>(true) {}));
    ;

    protected TransparentUpgradeableProxy(String contractAddress, Client client,
            CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public static String getABI() {
        return ABI;
    }

    public List<AdminChangedEventResponse> getAdminChangedEvents(
            TransactionReceipt transactionReceipt) {
        List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(ADMINCHANGED_EVENT, transactionReceipt);
        ArrayList<AdminChangedEventResponse> responses = new ArrayList<AdminChangedEventResponse>(valueList.size());
        for (Contract.EventValuesWithLog eventValues : valueList) {
            AdminChangedEventResponse typedResponse = new AdminChangedEventResponse();
            typedResponse.log = eventValues.getLog();
            typedResponse.previousAdmin = (String) eventValues.getNonIndexedValues().get(0).getValue();
            typedResponse.newAdmin = (String) eventValues.getNonIndexedValues().get(1).getValue();
            responses.add(typedResponse);
        }
        return responses;
    }

    public List<UpgradedEventResponse> getUpgradedEvents(TransactionReceipt transactionReceipt) {
        List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(UPGRADED_EVENT, transactionReceipt);
        ArrayList<UpgradedEventResponse> responses = new ArrayList<UpgradedEventResponse>(valueList.size());
        for (Contract.EventValuesWithLog eventValues : valueList) {
            UpgradedEventResponse typedResponse = new UpgradedEventResponse();
            typedResponse.log = eventValues.getLog();
            typedResponse.implementation = (String) eventValues.getIndexedValues().get(0).getValue();
            responses.add(typedResponse);
        }
        return responses;
    }

    public TransactionReceipt admin() {
        final Function function = new Function(
                FUNC_ADMIN,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String admin(TransactionCallback callback) {
        final Function function = new Function(
                FUNC_ADMIN,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForAdmin() {
        final Function function = new Function(
                FUNC_ADMIN,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple1<String> getAdminOutput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getOutput();
        final Function function = new Function(FUNC_ADMIN,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<String>(

                (String) results.get(0).getValue()
                );
    }

    public TransactionReceipt changeAdmin(String newAdmin) {
        final Function function = new Function(
                FUNC_CHANGEADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String changeAdmin(String newAdmin, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_CHANGEADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForChangeAdmin(String newAdmin) {
        final Function function = new Function(
                FUNC_CHANGEADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple1<String> getChangeAdminInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_CHANGEADMIN,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<String>(

                (String) results.get(0).getValue()
                );
    }

    public TransactionReceipt implementation() {
        final Function function = new Function(
                FUNC_IMPLEMENTATION,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String implementation(TransactionCallback callback) {
        final Function function = new Function(
                FUNC_IMPLEMENTATION,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForImplementation() {
        final Function function = new Function(
                FUNC_IMPLEMENTATION,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple1<String> getImplementationOutput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getOutput();
        final Function function = new Function(FUNC_IMPLEMENTATION,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<String>(

                (String) results.get(0).getValue()
                );
    }

    public TransactionReceipt upgradeTo(String newImplementation) {
        final Function function = new Function(
                FUNC_UPGRADETO,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String upgradeTo(String newImplementation, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_UPGRADETO,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForUpgradeTo(String newImplementation) {
        final Function function = new Function(
                FUNC_UPGRADETO,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple1<String> getUpgradeToInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_UPGRADETO,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<String>(

                (String) results.get(0).getValue()
                );
    }

    public TransactionReceipt upgradeToAndCall(String newImplementation, byte[] data) {
        final Function function = new Function(
                FUNC_UPGRADETOANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String upgradeToAndCall(String newImplementation, byte[] data,
            TransactionCallback callback) {
        final Function function = new Function(
                FUNC_UPGRADETOANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForUpgradeToAndCall(String newImplementation, byte[] data) {
        final Function function = new Function(
                FUNC_UPGRADETOANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newImplementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple2<String, byte[]> getUpgradeToAndCallInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_UPGRADETOANDCALL,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<DynamicBytes>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, byte[]>(

                (String) results.get(0).getValue(),
                (byte[]) results.get(1).getValue()
                );
    }

    public static TransparentUpgradeableProxy load(String contractAddress, Client client,
            CryptoKeyPair credential) {
        return new TransparentUpgradeableProxy(contractAddress, client, credential);
    }

    public static TransparentUpgradeableProxy deploy(Client client, CryptoKeyPair credential,
            String _logic, String _adm, byte[] _data) throws ContractException {
        byte[] encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(_logic),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(_adm),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(_data)));
        return deploy(TransparentUpgradeableProxy.class, client, credential, getBinary(client.getCryptoSuite()), getABI(), encodedConstructor, null);
    }

    public static class AdminChangedEventResponse {
        public TransactionReceipt.Logs log;

        public String previousAdmin;

        public String newAdmin;
    }

    public static class UpgradedEventResponse {
        public TransactionReceipt.Logs log;

        public String implementation;
    }
}
